package com.toolkit.exceptionHandler;
import com.toolkit.common.CommonRespBean;
import com.toolkit.enumData.ExceptionCodeMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = {Exception.class})
    @ResponseBody
    public <T> CommonRespBean<T> exceptionHandler(Exception e){
        //这里先判断拦截到的Exception是不是我们自定义的异常类型
        if(e instanceof BusinessException){
            BusinessException appException = (BusinessException)e;
            return CommonRespBean.error(appException.getCode(),appException.getMsg());
        } else if(e instanceof BindException){
            log.error("",e);
            //validate返回的错误信息
            String errorMsg = ((BindException)e).getBindingResult().getFieldError().getDefaultMessage();
            return CommonRespBean.error(500, errorMsg);
        } else if(e instanceof IllegalArgumentException){
            log.error("",e);
            //validate返回的错误信息
            String errorMsg = e.getMessage();
            return CommonRespBean.error(500, errorMsg);
        } else if(e instanceof ValidationException){
            log.error("",e);
            //validate返回的错误信息
            String errorMsg = e.getMessage();
            return CommonRespBean.error(500, errorMsg);
        }

        log.error("",e);
        //如果拦截的异常不是我们自定义的异常(例如：数据库主键冲突)
        return CommonRespBean.error(ExceptionCodeMsg.SERVER_ERROR_CODE);
    }

    /**
     * 处理所有校验失败的异常（MethodArgumentNotValidException异常）
     * 设置响应状态码为400
     * @param ex
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public <T> CommonRespBean<T> handleBindGetException(MethodArgumentNotValidException ex) {
        // 获取所有异常
        List<String> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(x -> x.getDefaultMessage())
                .collect(Collectors.toList());
        return CommonRespBean.error(ExceptionCodeMsg.SERVER_ERROR_CODE.getCode(), String.join(",", errors));
    }

    /**
     * 处理所有参数校验时抛出的异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(value = ValidationException.class)
    @ResponseBody
    public <T> CommonRespBean<T> handleBindException(ValidationException ex) {
        // 获取所有异常
        List<String> errors = new LinkedList<String>();
        if(ex instanceof ConstraintViolationException){
            ConstraintViolationException exs = (ConstraintViolationException) ex;
            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                errors.add(item.getMessage());
            }
        }
        return CommonRespBean.error(ExceptionCodeMsg.SERVER_ERROR_CODE.getCode(), String.join(",", errors));
    }

    /**
     * Controller参数绑定错误
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public <T> CommonRespBean<T> handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
        return CommonRespBean.error(ExceptionCodeMsg.SERVER_ERROR_CODE.getCode(), ex.getMessage());
    }
}
